home *** CD-ROM | disk | FTP | other *** search
/ The Complete Utilities To…ka 501 Killer Utilities! / 501 Killer Utilities! (Macworld July 1995).cdr / Programming / Glypha III Src / Code / Enemy.c next >
Encoding:
Text File  |  1995-02-03  |  29.2 KB  |  1,239 lines  |  [TEXT/MMCC]

  1.  
  2. //============================================================================
  3. //----------------------------------------------------------------------------
  4. //                                    Enemy.c
  5. //----------------------------------------------------------------------------
  6. //============================================================================
  7.  
  8.  
  9. #include "Externs.h"
  10.  
  11.  
  12. #define kEnemyImpulse            8
  13.  
  14. #define kOwlMaxHVel                96
  15. #define kOwlMaxVVel                320
  16. #define kOwlHeightSmell            96
  17. #define kOwlFlapImpulse            32
  18.  
  19. #define kWolfMaxHVel            128
  20. #define kWolfMaxVVel            400
  21. #define kWolfHeightSmell        160
  22. #define kWolfFlapImpulse        48
  23.  
  24. #define kJackalMaxHVel            192
  25. #define kJackalMaxVVel            512
  26. #define kJackalHeightSmell        240
  27. #define kJackalFlapImpulse        72
  28.  
  29.  
  30. Boolean SetEnemyInitialLocation (Rect *);
  31. void SetEnemyAttributes (short);
  32. short AssignNewAltitude (void);
  33. void InitEnemy (short, Boolean);
  34. void CheckEnemyPlatformHit (short);
  35. void CheckEnemyRoofCollision (short);
  36. void HandleIdleEnemies (short);
  37. void HandleFlyingEnemies (short);
  38. void HandleWalkingEnemy (short);
  39. void HandleSpawningEnemy (short);
  40. void HandleFallingEnemy (short);
  41. void HandleEggEnemy (short);
  42. void ResolveEnemyPlayerHit (short);
  43.  
  44.  
  45. handInfo    theHand;
  46. eyeInfo        theEye;
  47. Rect        grabZone;
  48. short        deadEnemies, spawnedEnemies, numEnemiesThisLevel, numOwls;
  49.  
  50. extern    playerType    thePlayer;
  51. extern    enemyType    theEnemies[kMaxEnemies];
  52. extern    Rect        platformRects[6], enemyInitRects[5];
  53. extern    long        theScore;
  54. extern    short        numLedges, lightningCount, numEnemies, countDownTimer;
  55. extern    short        levelOn, lightH, lightV;
  56. extern    Boolean        evenFrame, doEnemyFlapSound, doEnemyScrapeSound;
  57.  
  58.  
  59. //==============================================================  Functions
  60. //--------------------------------------------------------------  SetEnemyInitialLocation
  61.  
  62. Boolean SetEnemyInitialLocation (Rect *theRect)
  63. {
  64.     short        where, possibilities;
  65.     Boolean        facing;
  66.     
  67.     possibilities = numLedges - 1;
  68.     where = RandomInt(possibilities);
  69.     *theRect = enemyInitRects[where];
  70.     
  71.     switch (where)
  72.     {
  73.         case 0:
  74.         case 2:
  75.         facing = TRUE;
  76.         break;
  77.         
  78.         case 3:
  79.         if (RandomInt(2) == 0)
  80.             facing = TRUE;
  81.         else
  82.             facing = FALSE;
  83.         break;
  84.         
  85.         default:
  86.         facing = FALSE;
  87.         break;
  88.     }
  89.     
  90.     if ((levelOn % 5) == 4)            // Egg Wave
  91.     {
  92.         theRect->left += 12 + RandomInt(48) - 24;
  93.         theRect->right = theRect->left + 24;
  94.         theRect->top = theRect->bottom - 24;
  95.     }
  96.     
  97.     return (facing);
  98. }
  99.  
  100. //--------------------------------------------------------------  SetEnemyAttributes
  101.  
  102. void SetEnemyAttributes (short i)
  103. {
  104.     short        h;
  105.     
  106.     h = (theEnemies[i].dest.left + theEnemies[i].dest.right) >> 1;
  107.     if (h < 320)
  108.         theEnemies[i].facingRight = TRUE;
  109.     else
  110.         theEnemies[i].facingRight = FALSE;
  111.     
  112.     switch (theEnemies[i].kind)
  113.     {
  114.         case kOwl:
  115.         if (theEnemies[i].facingRight)
  116.             theEnemies[i].srcNum = 0;
  117.         else
  118.             theEnemies[i].srcNum = 2;
  119.         theEnemies[i].maxHVel = kOwlMaxHVel;
  120.         theEnemies[i].maxVVel = kOwlMaxVVel;
  121.         theEnemies[i].heightSmell = kOwlHeightSmell;
  122.         theEnemies[i].flapImpulse = kOwlFlapImpulse;
  123.         break;
  124.         
  125.         case kWolf:
  126.         if (theEnemies[i].facingRight)
  127.             theEnemies[i].srcNum = 4;
  128.         else
  129.             theEnemies[i].srcNum = 6;
  130.         theEnemies[i].maxHVel = kWolfMaxHVel;
  131.         theEnemies[i].maxVVel = kWolfMaxVVel;
  132.         theEnemies[i].heightSmell = kWolfHeightSmell;
  133.         theEnemies[i].flapImpulse = kWolfFlapImpulse;
  134.         break;
  135.         
  136.         case kJackal:
  137.         if (theEnemies[i].facingRight)
  138.             theEnemies[i].srcNum = 8;
  139.         else
  140.             theEnemies[i].srcNum = 10;
  141.         theEnemies[i].maxHVel = kJackalMaxHVel;
  142.         theEnemies[i].maxVVel = kJackalMaxVVel;
  143.         theEnemies[i].heightSmell = kJackalHeightSmell;
  144.         theEnemies[i].flapImpulse = kJackalFlapImpulse;
  145.         break;
  146.     }
  147. }
  148.  
  149. //--------------------------------------------------------------  AssignNewAltitude
  150.  
  151. short AssignNewAltitude (void)
  152. {
  153.     short        which, altitude;
  154.     
  155.     which = RandomInt(4);
  156.     switch (which)
  157.     {
  158.         case 0:
  159.         altitude = 65 << 4;
  160.         break;
  161.         
  162.         case 1:
  163.         altitude = 150 << 4;
  164.         break;
  165.         
  166.         case 2:
  167.         altitude = 245 << 4;
  168.         break;
  169.         
  170.         case 3:
  171.         altitude = 384 << 4;
  172.         break;
  173.     }
  174.     
  175.     return (altitude);
  176. }
  177.  
  178. //--------------------------------------------------------------  InitEnemy
  179.  
  180. void InitEnemy (short i, Boolean reincarnated)
  181. {
  182.     Boolean        facing;
  183.     
  184.     if (spawnedEnemies < numEnemiesThisLevel)
  185.     {
  186.         facing = SetEnemyInitialLocation(&theEnemies[i].dest);
  187.         theEnemies[i].wasDest = theEnemies[i].dest;
  188.         theEnemies[i].h = theEnemies[i].dest.left << 4;
  189.         theEnemies[i].v = theEnemies[i].dest.top << 4;
  190.         theEnemies[i].wasH = theEnemies[i].h;
  191.         theEnemies[i].wasV = theEnemies[i].v;
  192.         theEnemies[i].targetAlt = theEnemies[i].v - (40 << 4);
  193.         theEnemies[i].hVel = 0;
  194.         theEnemies[i].vVel = 0;
  195.         theEnemies[i].pass = 0;
  196.         if ((levelOn % 5) == 4)            // Egg Wave
  197.             theEnemies[i].mode = kEggTimer;
  198.         else
  199.             theEnemies[i].mode = kIdle;
  200.         if (i < numOwls)
  201.             theEnemies[i].kind = kOwl;
  202.         else if (i > (numOwls + 6))
  203.             theEnemies[i].kind = kJackal;
  204.         else
  205.             theEnemies[i].kind = kWolf;
  206.         theEnemies[i].facingRight = facing;
  207.         SetEnemyAttributes(i);
  208.         
  209.         if (reincarnated)
  210.             theEnemies[i].frame = RandomInt(48) + 8 + (numOwls * 32);
  211.         else
  212.             theEnemies[i].frame = RandomInt(48) + 32 + (64 * i) + (numOwls * 32);
  213.         
  214.         if ((levelOn % 5) == 4)            // Egg Wave
  215.             theEnemies[i].kind--;
  216.         
  217.         spawnedEnemies++;
  218.     }
  219. }
  220.  
  221. //--------------------------------------------------------------  GenerateEnemies
  222.  
  223. void GenerateEnemies (void)
  224. {
  225.     short        i;
  226.     
  227.     if ((levelOn % 5) == 4)            // Egg Wave
  228.     {
  229.         numEnemies = kMaxEnemies;
  230.         numEnemiesThisLevel = numEnemies;
  231.     }
  232.     else
  233.     {
  234.         numEnemies = ((levelOn / 5) + 2) * 2;
  235.         if (numEnemies > kMaxEnemies)
  236.             numEnemies = kMaxEnemies;
  237.         numEnemiesThisLevel = numEnemies * 2;
  238.     }
  239.     
  240.     deadEnemies = 0;
  241.     
  242.     numOwls = 4 - ((levelOn + 2) / 5);
  243.     if (numOwls < 0)
  244.         numOwls = 0;
  245.     
  246.     spawnedEnemies = 0;
  247.     
  248.     for (i = 0; i < numEnemies; i++)
  249.         InitEnemy(i, FALSE);
  250. }
  251.  
  252. //--------------------------------------------------------------  CheckEnemyPlatformHit
  253.  
  254. void CheckEnemyPlatformHit (short h)
  255. {
  256.     Rect        hRect, vRect, whoCares;
  257.     short        i, offset;
  258.     
  259.     for (i = 0; i < numLedges; i++)
  260.     {
  261.         if (SectRect(&theEnemies[h].dest, &platformRects[i], &whoCares))
  262.         {
  263.             hRect.left = theEnemies[h].dest.left;
  264.             hRect.right = theEnemies[h].dest.right;
  265.             hRect.top = theEnemies[h].wasDest.top;
  266.             hRect.bottom = theEnemies[h].wasDest.bottom;
  267.             
  268.             if (SectRect(&hRect, &platformRects[i], &whoCares))
  269.             {
  270.                 if (theEnemies[h].h > theEnemies[h].wasH)    // moving to right
  271.                 {
  272.                     offset = theEnemies[h].dest.right - platformRects[i].left;
  273.                     theEnemies[h].dest.left -= offset;
  274.                     theEnemies[h].dest.right -= offset;
  275.                     theEnemies[h].h = theEnemies[h].dest.left << 4;
  276.                     theEnemies[h].wasH = theEnemies[h].h;
  277.                     if (theEnemies[h].hVel > 0)
  278.                         theEnemies[h].hVel = -(theEnemies[h].hVel >> 1);
  279.                     else
  280.                         theEnemies[h].hVel = theEnemies[h].hVel >> 1;
  281.                 }
  282.                 if (theEnemies[h].h < theEnemies[h].wasH)    // moving to left
  283.                 {
  284.                     offset = platformRects[i].right - theEnemies[h].dest.left;
  285.                     theEnemies[h].dest.left += offset;
  286.                     theEnemies[h].dest.right += offset;
  287.                     theEnemies[h].h = theEnemies[h].dest.left << 4;
  288.                     theEnemies[h].wasH = theEnemies[h].h;
  289.                     if (theEnemies[h].hVel < 0)
  290.                         theEnemies[h].hVel = -(theEnemies[h].hVel >> 1);
  291.                     else
  292.                         theEnemies[h].hVel = theEnemies[h].hVel >> 1;
  293.                 }
  294.                 doEnemyScrapeSound = TRUE;
  295.                 theEnemies[h].facingRight = !theEnemies[h].facingRight;
  296.             }
  297.             else
  298.             {
  299.                 vRect.left = theEnemies[h].wasDest.left;
  300.                 vRect.right = theEnemies[h].wasDest.right;
  301.                 vRect.top = theEnemies[h].dest.top;
  302.                 vRect.bottom = theEnemies[h].dest.bottom;
  303.                 
  304.                 if (SectRect(&vRect, &platformRects[i], &whoCares))
  305.                 {
  306.                     if (theEnemies[h].mode == kFalling)
  307.                     {
  308.                         theEnemies[i].hVel -= (theEnemies[i].hVel >> 3);
  309.                         if ((theEnemies[i].hVel < 8) && (theEnemies[i].hVel > -8))
  310.                         {
  311.                             if (theEnemies[i].hVel > 0)
  312.                                 theEnemies[i].hVel--;
  313.                             else if (theEnemies[i].hVel < 0)
  314.                                 theEnemies[i].hVel++;
  315.                         }
  316.                     }
  317.                     
  318.                     if (theEnemies[h].v > theEnemies[h].wasV)        // heading down
  319.                     {
  320.                         offset = theEnemies[h].dest.bottom - platformRects[i].top;
  321.                         theEnemies[h].dest.top -= offset;
  322.                         theEnemies[h].dest.bottom -= offset;
  323.                         theEnemies[h].v = theEnemies[h].dest.top << 4;
  324.                         theEnemies[h].wasV = theEnemies[h].v;
  325.                         if (theEnemies[h].vVel > kDontFlapVel)
  326.                             doEnemyScrapeSound = TRUE;
  327.                         if (theEnemies[h].vVel > 0)
  328.                             theEnemies[h].vVel = -(theEnemies[h].vVel >> 1);
  329.                         else
  330.                             theEnemies[h].vVel = theEnemies[h].vVel >> 1;
  331.                         if ((theEnemies[h].vVel < 8) && (theEnemies[h].vVel > -8) && 
  332.                                 (theEnemies[h].hVel == 0) && (theEnemies[h].mode == kFalling))
  333.                         {
  334.                             if (((theEnemies[h].dest.right - 8) > platformRects[i].right) && 
  335.                                     (theEnemies[h].hVel == 0))
  336.                             {                // if enemy has come to rest half off the edge…
  337.                                 theEnemies[h].hVel = 32;
  338.                             }
  339.                             else if (((theEnemies[h].dest.left + 8) < platformRects[i].left) && 
  340.                                     (theEnemies[h].hVel == 0))
  341.                             {
  342.                                 theEnemies[h].hVel = -32;
  343.                             }
  344.                             else
  345.                             {
  346.                                 theEnemies[h].mode = kEggTimer;
  347.                                 theEnemies[h].frame = (numOwls * 96) + 128;
  348.                                 theEnemies[h].vVel = 0;
  349.                             }
  350.                         }
  351.                     }
  352.                     if (theEnemies[h].v < theEnemies[h].wasV)        // heading up
  353.                     {
  354.                         offset = theEnemies[h].dest.top - platformRects[i].bottom;
  355.                         theEnemies[h].dest.top -= offset;
  356.                         theEnemies[h].dest.bottom -= offset;
  357.                         theEnemies[h].v = theEnemies[h].dest.top << 4;
  358.                         theEnemies[h].wasV = theEnemies[h].v;
  359.                         doEnemyScrapeSound = TRUE;
  360.                         if (theEnemies[h].vVel < 0)
  361.                             theEnemies[h].vVel = -(theEnemies[h].vVel >> 2);
  362.                         else
  363.                             theEnemies[h].vVel = theEnemies[h].vVel >> 2;
  364.                         if ((theEnemies[h].vVel < 8) && (theEnemies[h].vVel > -8) && 
  365.                                 (theEnemies[h].hVel == 0) && (theEnemies[h].mode == kFalling))
  366.                         {
  367.                             theEnemies[h].mode = kEggTimer;
  368.                             theEnemies[h].frame = (numOwls * 96) + 128;
  369.                             theEnemies[h].vVel = 0;
  370.                         }
  371.                     }
  372.                 }
  373.             }
  374.         }
  375.     }
  376. }
  377.  
  378. //--------------------------------------------------------------  CheckEnemyRoofCollision
  379.  
  380. void CheckEnemyRoofCollision (short i)
  381. {
  382.     short        offset;
  383.     
  384.     if (theEnemies[i].dest.top < (kRoofHeight - 2))
  385.     {
  386.         offset = kRoofHeight - theEnemies[i].dest.top;
  387.         theEnemies[i].dest.top += offset;
  388.         theEnemies[i].dest.bottom += offset;
  389.         theEnemies[i].v = theEnemies[i].dest.top << 4;
  390.         doEnemyScrapeSound = TRUE;
  391.         theEnemies[i].vVel = -(theEnemies[i].vVel >> 2);
  392.     }
  393.     else if (theEnemies[i].dest.top > kLavaHeight)
  394.     {
  395.         theEnemies[i].mode = kDeadAndGone;
  396.         deadEnemies++;
  397.         
  398.         PlayExternalSound(kSplashSound, kSplashPriority);
  399.         InitEnemy(i, TRUE);
  400.     }
  401. }
  402.  
  403. //--------------------------------------------------------------  HandleIdleEnemies
  404.  
  405. void HandleIdleEnemies (short i)
  406. {
  407.     theEnemies[i].frame--;
  408.     if (theEnemies[i].frame <= 0)
  409.     {
  410.         theEnemies[i].mode = kSpawning;
  411.         theEnemies[i].wasH = theEnemies[i].h;
  412.         theEnemies[i].wasV = theEnemies[i].v;
  413.         theEnemies[i].hVel = 0;
  414.         theEnemies[i].vVel = 0;
  415.         theEnemies[i].frame = 0;
  416.         SetEnemyAttributes(i);
  417.         PlayExternalSound(kSpawnSound, kSpawnPriority);
  418.     }
  419. }
  420.  
  421. //--------------------------------------------------------------  HandleFlyingEnemies
  422.  
  423. void HandleFlyingEnemies (short i)
  424. {
  425.     short        dist;
  426.     Boolean        shouldFlap;
  427.     
  428.     theEnemies[i].vVel += kGravity;
  429.     
  430.     dist = thePlayer.dest.top - theEnemies[i].dest.top;
  431.     if (dist < 0)
  432.         dist = -dist;
  433.     
  434.     if ((dist < theEnemies[i].heightSmell) && 
  435.             ((thePlayer.mode == kFlying) || (thePlayer.mode == kWalking)))
  436.     {                            // enemy will actively seek the player
  437.         if (thePlayer.dest.left < theEnemies[i].dest.left)
  438.         {
  439.             dist = theEnemies[i].dest.left - thePlayer.dest.left;
  440.             if (dist < 320)        // closest route is to the left
  441.                 theEnemies[i].facingRight = FALSE;
  442.             else                // closest route is to the right
  443.                 theEnemies[i].facingRight = TRUE;
  444.         }
  445.         else if (thePlayer.dest.left > theEnemies[i].dest.left)
  446.         {
  447.             dist = thePlayer.dest.left - theEnemies[i].dest.left;
  448.             if (dist < 320)        // closest route is to the right
  449.                 theEnemies[i].facingRight = TRUE;
  450.             else                // closest route is to the left
  451.                 theEnemies[i].facingRight = FALSE;
  452.         }
  453.                                 // seek point 16 pixels above player
  454.         if (((theEnemies[i].v + 16) > thePlayer.v) && (evenFrame))
  455.             shouldFlap = TRUE;
  456.         else
  457.             shouldFlap = FALSE;
  458.     }
  459.     else
  460.     {
  461.         if ((theEnemies[i].v > theEnemies[i].targetAlt) && (evenFrame))
  462.             shouldFlap = TRUE;
  463.         else
  464.             shouldFlap = FALSE;
  465.     }
  466.     
  467.     if (shouldFlap)
  468.     {
  469.         theEnemies[i].vVel -= theEnemies[i].flapImpulse;
  470.         doEnemyFlapSound = TRUE;
  471.     }
  472.     
  473.     if (theEnemies[i].facingRight)
  474.     {
  475.         theEnemies[i].hVel += kEnemyImpulse;
  476.         if (theEnemies[i].hVel > theEnemies[i].maxHVel)
  477.             theEnemies[i].hVel = theEnemies[i].maxHVel;
  478.         
  479.         switch (theEnemies[i].kind)
  480.         {
  481.             case kOwl:
  482.             if (shouldFlap)
  483.                 theEnemies[i].srcNum = 12;
  484.             else
  485.                 theEnemies[i].srcNum = 13;
  486.             break;
  487.             
  488.             case kWolf:
  489.             if (shouldFlap)
  490.                 theEnemies[i].srcNum = 16;
  491.             else
  492.                 theEnemies[i].srcNum = 17;
  493.             break;
  494.             
  495.             case kJackal:
  496.             if (shouldFlap)
  497.                 theEnemies[i].srcNum = 20;
  498.             else
  499.                 theEnemies[i].srcNum = 21;
  500.             break;
  501.         }
  502.         
  503.     }
  504.     else
  505.     {
  506.         theEnemies[i].hVel -= kEnemyImpulse;
  507.         if (theEnemies[i].hVel < -theEnemies[i].maxHVel)
  508.             theEnemies[i].hVel = -theEnemies[i].maxHVel;
  509.         
  510.         switch (theEnemies[i].kind)
  511.         {
  512.             case kOwl:
  513.             if (shouldFlap)
  514.                 theEnemies[i].srcNum = 14;
  515.             else
  516.                 theEnemies[i].srcNum = 15;
  517.             break;
  518.             
  519.             case kWolf:
  520.             if (shouldFlap)
  521.                 theEnemies[i].srcNum = 18;
  522.             else
  523.                 theEnemies[i].srcNum = 19;
  524.             break;
  525.             
  526.             case kJackal:
  527.             if (shouldFlap)
  528.                 theEnemies[i].srcNum = 22;
  529.             else
  530.                 theEnemies[i].srcNum = 23;
  531.             break;
  532.         }
  533.     }
  534.     
  535.     theEnemies[i].h += theEnemies[i].hVel;
  536.     theEnemies[i].dest.left = theEnemies[i].h >> 4;
  537.     theEnemies[i].dest.right = theEnemies[i].dest.left + 64;
  538.     
  539.     theEnemies[i].v += theEnemies[i].vVel;
  540.     theEnemies[i].dest.top = theEnemies[i].v >> 4;
  541.     theEnemies[i].dest.bottom = theEnemies[i].dest.top + 40;
  542.     
  543.     if (theEnemies[i].dest.left > 640)
  544.     {
  545.         OffsetRect(&theEnemies[i].dest, -640, 0);
  546.         theEnemies[i].h = theEnemies[i].dest.left << 4;
  547.         OffsetRect(&theEnemies[i].wasDest, -640, 0);
  548.         theEnemies[i].pass++;
  549.         if (theEnemies[i].pass > 2)        // after two screen passes…
  550.         {                                // enemy patrols a new altitude
  551.             theEnemies[i].targetAlt = AssignNewAltitude();
  552.             theEnemies[i].pass = 0;
  553.         }
  554.     }
  555.     else if (theEnemies[i].dest.right < 0)
  556.     {
  557.         OffsetRect(&theEnemies[i].dest, 640, 0);
  558.         theEnemies[i].h = theEnemies[i].dest.left << 4;
  559.         OffsetRect(&theEnemies[i].wasDest, 640, 0);
  560.         theEnemies[i].pass++;
  561.         if (theEnemies[i].pass > 2)
  562.         {
  563.             theEnemies[i].targetAlt = AssignNewAltitude();
  564.             theEnemies[i].pass = 0;
  565.         }
  566.     }
  567.     
  568.     theEnemies[i].vVel -= theEnemies[i].vVel >> 4;    // friction
  569.     
  570.     if (theEnemies[i].vVel > theEnemies[i].maxVVel)
  571.         theEnemies[i].vVel = theEnemies[i].maxVVel;
  572.     else if (theEnemies[i].vVel < -theEnemies[i].maxVVel)
  573.         theEnemies[i].vVel = -theEnemies[i].maxVVel;
  574.     
  575.     CheckEnemyRoofCollision(i);
  576.     CheckEnemyPlatformHit(i);
  577. }
  578.  
  579. //--------------------------------------------------------------  HandleWalkingEnemy
  580.  
  581. void HandleWalkingEnemy (short i)
  582. {
  583.     if (theEnemies[i].facingRight)
  584.     {
  585.         theEnemies[i].dest.left += 6;
  586.         theEnemies[i].dest.right += 6;
  587.         switch (theEnemies[i].kind)
  588.         {
  589.             case kOwl:
  590.             theEnemies[i].srcNum = 1 - theEnemies[i].srcNum;
  591.             break;
  592.             
  593.             case kWolf:
  594.             theEnemies[i].srcNum = 9 - theEnemies[i].srcNum;
  595.             break;
  596.             
  597.             case kJackal:
  598.             theEnemies[i].srcNum = 17 - theEnemies[i].srcNum;
  599.             break;
  600.         }
  601.         theEnemies[i].hVel = 6 << 4;
  602.     }
  603.     else
  604.     {
  605.         theEnemies[i].dest.left -= 6;
  606.         theEnemies[i].dest.right -= 6;
  607.         switch (theEnemies[i].kind)
  608.         {
  609.             case kOwl:
  610.             theEnemies[i].srcNum = 5 - theEnemies[i].srcNum;
  611.             break;
  612.             
  613.             case kWolf:
  614.             theEnemies[i].srcNum = 13 - theEnemies[i].srcNum;
  615.             break;
  616.             
  617.             case kJackal:
  618.             theEnemies[i].srcNum = 21 - theEnemies[i].srcNum;
  619.             break;
  620.         }
  621.         theEnemies[i].hVel = -6 << 4;
  622.     }
  623.     theEnemies[i].frame++;
  624.     if (theEnemies[i].frame >= 8)
  625.     {
  626.         theEnemies[i].mode = kFlying;
  627.         theEnemies[i].frame = 0;
  628.         switch (theEnemies[i].kind)
  629.         {
  630.             case kOwl:
  631.             if (theEnemies[i].facingRight)
  632.                 theEnemies[i].srcNum = 12;
  633.             else
  634.                 theEnemies[i].srcNum = 14;
  635.             break;
  636.             
  637.             case kWolf:
  638.             if (theEnemies[i].facingRight)
  639.                 theEnemies[i].srcNum = 16;
  640.             else
  641.                 theEnemies[i].srcNum = 18;
  642.             break;
  643.             
  644.             case kJackal:
  645.             if (theEnemies[i].facingRight)
  646.                 theEnemies[i].srcNum = 20;
  647.             else
  648.                 theEnemies[i].srcNum = 22;
  649.             break;
  650.         }
  651.         
  652.         theEnemies[i].dest.left -= 8;
  653.         theEnemies[i].dest.right += 8;
  654.         theEnemies[i].dest.bottom = theEnemies[i].dest.top + 40;
  655.         theEnemies[i].h = theEnemies[i].dest.left * 16;
  656.         theEnemies[i].v = theEnemies[i].dest.top * 16;
  657.     }
  658. }
  659.  
  660. //--------------------------------------------------------------  HandleSpawningEnemy
  661.  
  662. void HandleSpawningEnemy (short i)
  663. {
  664.     theEnemies[i].frame++;
  665.     if (theEnemies[i].frame >= 48)
  666.     {
  667.         theEnemies[i].mode = kWalking;
  668.         theEnemies[i].frame = 0;
  669.         
  670.         switch (theEnemies[i].kind)
  671.         {
  672.             case kOwl:
  673.             if (theEnemies[i].facingRight)
  674.                 theEnemies[i].srcNum = 0;
  675.             else
  676.                 theEnemies[i].srcNum = 2;
  677.             break;
  678.             
  679.             case kWolf:
  680.             if (theEnemies[i].facingRight)
  681.                 theEnemies[i].srcNum = 4;
  682.             else
  683.                 theEnemies[i].srcNum = 6;
  684.             break;
  685.             
  686.             case kJackal:
  687.             if (theEnemies[i].facingRight)
  688.                 theEnemies[i].srcNum = 8;
  689.             else
  690.                 theEnemies[i].srcNum = 10;
  691.             break;
  692.         }
  693.     }
  694.     else
  695.         theEnemies[i].dest.top = theEnemies[i].dest.bottom - theEnemies[i].frame;
  696. }
  697.  
  698. //--------------------------------------------------------------  HandleFallingEnemy
  699.  
  700. void HandleFallingEnemy (short i)
  701. {
  702.     theEnemies[i].vVel += kGravity;
  703.     
  704.     if (theEnemies[i].vVel > theEnemies[i].maxVVel)
  705.         theEnemies[i].vVel = theEnemies[i].maxVVel;
  706.     else if (theEnemies[i].vVel < -theEnemies[i].maxVVel)
  707.         theEnemies[i].vVel = -theEnemies[i].maxVVel;
  708.     
  709.     if (evenFrame)
  710.     {
  711.         theEnemies[i].hVel -= (theEnemies[i].hVel >> 5);
  712.         if ((theEnemies[i].hVel < 32) && (theEnemies[i].hVel > -32))
  713.         {
  714.             if (theEnemies[i].hVel > 0)
  715.                 theEnemies[i].hVel--;
  716.             else if (theEnemies[i].hVel < 0)
  717.                 theEnemies[i].hVel++;
  718.         }
  719.     }
  720.     
  721.     theEnemies[i].h += theEnemies[i].hVel;
  722.     theEnemies[i].dest.left = theEnemies[i].h >> 4;
  723.     theEnemies[i].dest.right = theEnemies[i].dest.left + 24;
  724.     
  725.     theEnemies[i].v += theEnemies[i].vVel;
  726.     theEnemies[i].dest.top = theEnemies[i].v >> 4;
  727.     theEnemies[i].dest.bottom = theEnemies[i].dest.top + 24;
  728.     
  729.     if (theEnemies[i].dest.left > 640)
  730.     {
  731.         OffsetRect(&theEnemies[i].dest, -640, 0);
  732.         theEnemies[i].h = theEnemies[i].dest.left << 4;
  733.         OffsetRect(&theEnemies[i].wasDest, -640, 0);
  734.     }
  735.     else if (theEnemies[i].dest.right < 0)
  736.     {
  737.         OffsetRect(&theEnemies[i].dest, 640, 0);
  738.         theEnemies[i].h = theEnemies[i].dest.left << 4;
  739.         OffsetRect(&theEnemies[i].wasDest, 640, 0);
  740.     }
  741.     
  742.     CheckEnemyRoofCollision(i);
  743.     CheckEnemyPlatformHit(i);
  744. }
  745.  
  746. //--------------------------------------------------------------  HandleEggEnemy
  747.  
  748. void HandleEggEnemy (short i)
  749. {
  750.     short        center;
  751.     
  752.     theEnemies[i].frame--;
  753.     if (theEnemies[i].frame < 24)
  754.     {
  755.         theEnemies[i].dest.top = theEnemies[i].dest.bottom - theEnemies[i].frame;
  756.         if (theEnemies[i].frame == 0)        // a sphinx is born!
  757.         {
  758.             theEnemies[i].frame = 0;
  759.             PlayExternalSound(kSpawnSound, kSpawnPriority);
  760.             center = (theEnemies[i].dest.left + theEnemies[i].dest.right) >> 1;
  761.             theEnemies[i].dest.left = center - 24;
  762.             theEnemies[i].dest.right = center + 24;
  763.             theEnemies[i].wasDest = theEnemies[i].dest;
  764.             theEnemies[i].h = theEnemies[i].dest.left << 4;
  765.             theEnemies[i].v = theEnemies[i].dest.top << 4;
  766.             theEnemies[i].wasH = theEnemies[i].h;
  767.             theEnemies[i].wasV = theEnemies[i].v;
  768.             theEnemies[i].hVel = 0;
  769.             theEnemies[i].vVel = 0;
  770.             theEnemies[i].mode = kSpawning;
  771.             theEnemies[i].kind++;
  772.             if (theEnemies[i].kind > kJackal)
  773.                 theEnemies[i].kind = kJackal;
  774.             SetEnemyAttributes(i);
  775.         }
  776.     }
  777. }
  778.  
  779. //--------------------------------------------------------------  MoveEnemies
  780.  
  781. void MoveEnemies (void)
  782. {
  783.     short        i;
  784.     
  785.     doEnemyFlapSound = FALSE;
  786.     doEnemyScrapeSound = FALSE;
  787.     
  788.     for (i = 0; i < numEnemies; i++)
  789.     {
  790.         switch (theEnemies[i].mode)
  791.         {
  792.             case kIdle:
  793.             HandleIdleEnemies(i);
  794.             break;
  795.             
  796.             case kFlying:
  797.             HandleFlyingEnemies(i);
  798.             break;
  799.             
  800.             case kWalking:
  801.             HandleWalkingEnemy(i);
  802.             break;
  803.             
  804.             case kSpawning:
  805.             HandleSpawningEnemy(i);
  806.             break;
  807.             
  808.             case kFalling:
  809.             HandleFallingEnemy(i);
  810.             break;
  811.             
  812.             case kEggTimer:
  813.             HandleEggEnemy(i);
  814.             break;
  815.             
  816.             case kDeadAndGone:
  817.             break;
  818.         }
  819.     }
  820.     
  821.     if (doEnemyFlapSound)
  822.         PlayExternalSound(kFlap2Sound, kFlap2Priority);
  823.     if (doEnemyScrapeSound)
  824.         PlayExternalSound(kScrape2Sound, kScrape2Priority);
  825.     if ((deadEnemies >= numEnemiesThisLevel) && (countDownTimer == 0))
  826.         countDownTimer = 30;
  827. }
  828.  
  829. //--------------------------------------------------------------  InitHandLocation
  830.  
  831. void InitHandLocation (void)
  832. {
  833.     SetRect(&theHand.dest, 0, 0, 56, 57);
  834.     OffsetRect(&theHand.dest, 48, 460);
  835. }
  836.  
  837. //--------------------------------------------------------------  HandleHand
  838.  
  839. void HandleHand (void)
  840. {
  841.     Rect        whoCares;
  842.     short        hDiff, vDiff, pull, speed;
  843.     
  844.     switch (theHand.mode)
  845.     {
  846.         case kLurking:
  847.         if ((thePlayer.mode == kFlying) && (SectRect(&thePlayer.dest, &grabZone, &whoCares)))
  848.         {
  849.             theHand.mode = kOutGrabeth;
  850.             InitHandLocation();
  851.         }
  852.         break;
  853.         
  854.         case kOutGrabeth:
  855.         case kClutching:
  856.         if (SectRect(&thePlayer.dest, &grabZone, &whoCares))
  857.         {
  858.             hDiff = theHand.dest.left - thePlayer.dest.left;
  859.             vDiff = theHand.dest.top - thePlayer.dest.top;
  860.             
  861.             if (thePlayer.facingRight)
  862.                 hDiff -= 3;
  863.             else
  864.                 hDiff -= 21;
  865.             vDiff -= 29;
  866.             
  867.             speed = (levelOn >> 3) + 1;
  868.             if (hDiff < 0)
  869.             {
  870.                 theHand.dest.left += speed;
  871.                 theHand.dest.right += speed;
  872.             }
  873.             else if (hDiff > 0)
  874.             {
  875.                 theHand.dest.left -= speed;
  876.                 theHand.dest.right -= speed;
  877.             }
  878.             if (vDiff < 0)
  879.             {
  880.                 theHand.dest.top += speed;
  881.                 theHand.dest.bottom += speed;
  882.             }
  883.             else if (vDiff > 0)
  884.             {
  885.                 theHand.dest.top -= speed;
  886.                 theHand.dest.bottom -= speed;
  887.             }
  888.             
  889.             if (hDiff < 0)
  890.                 hDiff = -hDiff;
  891.             if (vDiff < 0)
  892.                 vDiff = -vDiff;
  893.             if ((hDiff < 8) && (vDiff < 8))
  894.             {
  895.                 theHand.mode = kClutching;
  896.                 thePlayer.clutched = TRUE;
  897.                 thePlayer.hVel = thePlayer.hVel >> 3;
  898.                 thePlayer.vVel = thePlayer.vVel >> 3;
  899.                 pull = levelOn << 2;
  900.                 if (pull > 48)
  901.                     pull = 48;
  902.                 thePlayer.vVel += pull;
  903.                 theHand.dest.top = thePlayer.dest.top + 29;
  904.                 theHand.dest.bottom = theHand.dest.top + 57;
  905.                 if (thePlayer.facingRight)
  906.                     theHand.dest.left = thePlayer.dest.left + 3;
  907.                 else
  908.                     theHand.dest.left = thePlayer.dest.left + 21;
  909.                 theHand.dest.right = theHand.dest.left + 58;
  910.             }
  911.             else
  912.             {
  913.                 thePlayer.clutched = FALSE;
  914.                 theHand.mode = kOutGrabeth;
  915.             }
  916.         }
  917.         else
  918.         {
  919.             theHand.dest.top++;
  920.             theHand.dest.bottom++;
  921.             if (theHand.dest.top > 460)
  922.                 theHand.mode = kLurking;
  923.             else
  924.                 theHand.mode = kOutGrabeth;
  925.             thePlayer.clutched = FALSE;
  926.         }
  927.         break;
  928.     }
  929. }
  930.  
  931. //--------------------------------------------------------------  InitEye
  932.  
  933. void InitEye (void)
  934. {
  935.     SetRect(&theEye.dest, 0, 0, 48, 31);
  936.     OffsetRect(&theEye.dest, 296, 97);
  937.     theEye.mode = kWaiting;
  938.     theEye.frame = (numOwls + 2) * 720;
  939.     theEye.srcNum = 0;
  940.     theEye.opening = 1;
  941.     theEye.killed = FALSE;
  942.     theEye.entering = FALSE;
  943. }
  944.  
  945. //--------------------------------------------------------------  KillOffEye
  946.  
  947. void KillOffEye (void)
  948. {
  949.     if (theEye.mode == kStalking)
  950.     {
  951.         theEye.killed = TRUE;
  952.         theEye.opening = 1;
  953.         theEye.entering = FALSE;
  954.         if (theEye.srcNum == 0)
  955.             theEye.srcNum = 1;
  956.     }
  957.     else
  958.         InitEye();
  959. }
  960.  
  961. //--------------------------------------------------------------  HandleEye
  962.  
  963. void HandleEye (void)
  964. {
  965.     short        diffH, diffV, speed;
  966.     
  967.     if (theEye.mode == kStalking)        // eye is about
  968.     {
  969.         speed = (levelOn >> 4) + 1;
  970.         if (speed > 3)
  971.             speed = 3;
  972.         
  973.         if ((theEye.killed) || (theEye.entering))
  974.         {
  975.             speed = 0;
  976.         }
  977.         else if ((thePlayer.mode != kFlying) && (thePlayer.mode != kWalking))
  978.         {
  979.             diffH = theEye.dest.left - 296;
  980.             diffV = theEye.dest.bottom - 128;
  981.         }
  982.         else
  983.         {
  984.             diffH = theEye.dest.left - thePlayer.dest.left;
  985.             diffV = theEye.dest.bottom - thePlayer.dest.bottom;
  986.         }
  987.         
  988.         if (diffH > 0)
  989.         {
  990.             if (diffH < speed)
  991.                 theEye.dest.left -= diffH;
  992.             else
  993.                 theEye.dest.left -= speed;
  994.             theEye.dest.right = theEye.dest.left + 48;
  995.         }
  996.         else if (diffH < 0)
  997.         {
  998.             if (-diffH < speed)
  999.                 theEye.dest.left -= diffH;
  1000.             else
  1001.                 theEye.dest.left += speed;
  1002.             theEye.dest.right = theEye.dest.left + 48;
  1003.         }
  1004.         if (diffV > 0)
  1005.         {
  1006.             if (diffV < speed)
  1007.                 theEye.dest.bottom -= diffV;
  1008.             else
  1009.                 theEye.dest.bottom -= speed;
  1010.             theEye.dest.top = theEye.dest.bottom - 31;
  1011.         }
  1012.         else if (diffV < 0)
  1013.         {
  1014.             if (-diffV < speed)
  1015.                 theEye.dest.bottom -= diffV;
  1016.             else
  1017.                 theEye.dest.bottom += speed;
  1018.             theEye.dest.top = theEye.dest.bottom - 31;
  1019.         }
  1020.         
  1021.         theEye.frame++;
  1022.         
  1023.         if (theEye.srcNum != 0)
  1024.         {
  1025.             if (theEye.frame > 3)        // eye-closing frame holds for 3 frames
  1026.             {
  1027.                 theEye.frame = 0;
  1028.                 theEye.srcNum += theEye.opening;
  1029.                 if (theEye.srcNum > 3)
  1030.                 {
  1031.                     theEye.srcNum = 3;
  1032.                     theEye.opening = -1;
  1033.                     if (theEye.killed)
  1034.                         InitEye();
  1035.                 }
  1036.                 else if (theEye.srcNum <= 0)
  1037.                 {
  1038.                     theEye.srcNum = 0;
  1039.                     theEye.opening = 1;
  1040.                     theEye.frame = 0;
  1041.                     theEye.entering = FALSE;
  1042.                 }
  1043.             }
  1044.         }
  1045.         else if (theEye.frame > 256)
  1046.         {
  1047.             theEye.srcNum = 1;
  1048.             theEye.opening = 1;
  1049.             theEye.frame = 0;
  1050.         }
  1051.         
  1052.         diffH = theEye.dest.left - thePlayer.dest.left;
  1053.         diffV = theEye.dest.bottom - thePlayer.dest.bottom;
  1054.         if (diffH < 0)
  1055.             diffH = -diffH;
  1056.         if (diffV < 0)
  1057.             diffV = -diffV;
  1058.         
  1059.         if ((diffH < 16) && (diffV < 16) && (!theEye.entering) && 
  1060.                 (!theEye.killed))            // close enough to call it a kill
  1061.         {
  1062.             if (theEye.srcNum == 0)            // if eye open, player is killed
  1063.             {
  1064.                 if (lightningCount == 0)
  1065.                 {
  1066.                     lightH = thePlayer.dest.left + 24;
  1067.                     lightV = thePlayer.dest.bottom - 24;
  1068.                     lightningCount = 6;
  1069.                 }
  1070.                 thePlayer.mode = kFalling;
  1071.                 if (thePlayer.facingRight)
  1072.                     thePlayer.srcNum = 8;
  1073.                 else
  1074.                     thePlayer.srcNum = 9;
  1075.                 thePlayer.dest.bottom = thePlayer.dest.top + 37;
  1076.                 PlayExternalSound(kBoom2Sound, kBoom2Priority);
  1077.             }
  1078.             else                            // wow, player killed the eye
  1079.             {
  1080.                 if (lightningCount == 0)
  1081.                 {
  1082.                     lightH = theEye.dest.left + 24;
  1083.                     lightV = theEye.dest.top + 16;
  1084.                     lightningCount = 15;
  1085.                 }
  1086.                 theScore += 2000L;
  1087.                 UpdateScoreNumbers();
  1088.                 PlayExternalSound(kBonusSound, kBonusPriority);
  1089.                 
  1090.                 KillOffEye();
  1091.             }
  1092.         }
  1093.     }
  1094.     else if (theEye.frame > 0)
  1095.     {
  1096.         theEye.frame--;
  1097.         if (theEye.frame == 0)            // eye appears
  1098.         {
  1099.             theEye.mode = kStalking;
  1100.             if (lightningCount == 0)
  1101.             {
  1102.                 lightH = theEye.dest.left + 24;
  1103.                 lightV = theEye.dest.top + 16;
  1104.                 lightningCount = 6;
  1105.             }
  1106.             theEye.srcNum = 3;
  1107.             theEye.opening = 1;
  1108.             theEye.entering = TRUE;
  1109.         }
  1110.     }    
  1111. }
  1112.  
  1113. //--------------------------------------------------------------  ResolveEnemyPlayerHit
  1114.  
  1115. void ResolveEnemyPlayerHit (short i)
  1116. {
  1117.     short        wasVel, diff, h, v;
  1118.     
  1119.     if ((theEnemies[i].mode == kFalling) || (theEnemies[i].mode == kEggTimer))
  1120.     {
  1121.         deadEnemies++;
  1122.         
  1123.         theEnemies[i].mode = kDeadAndGone;
  1124.         theScore += 500L;
  1125.         UpdateScoreNumbers();
  1126.         PlayExternalSound(kBonusSound, kBonusPriority);
  1127.         InitEnemy(i, TRUE);
  1128.     }
  1129.     else
  1130.     {
  1131.         diff = (theEnemies[i].dest.top + 25) - (thePlayer.dest.top + 19);
  1132.         
  1133.         if (diff < -2)        // player is bested
  1134.         {
  1135.             if (lightningCount == 0)
  1136.             {
  1137.                 lightH = thePlayer.dest.left + 24;
  1138.                 lightV = thePlayer.dest.bottom - 24;
  1139.                 lightningCount = 6;
  1140.             }
  1141.             
  1142.             thePlayer.mode = kFalling;
  1143.             if (thePlayer.facingRight)
  1144.                 thePlayer.srcNum = 8;
  1145.             else
  1146.                 thePlayer.srcNum = 9;
  1147.             thePlayer.dest.bottom = thePlayer.dest.top + 37;
  1148.             PlayExternalSound(kBoom2Sound, kBoom2Priority);
  1149.         }
  1150.         else if (diff > 2)    // enemy killed
  1151.         {
  1152.             if ((theEnemies[i].mode == kSpawning) && (theEnemies[i].frame < 16))
  1153.                 return;
  1154.             
  1155.             h = (theEnemies[i].dest.left + theEnemies[i].dest.right) >> 1;
  1156.             if (theEnemies[i].mode == kSpawning)
  1157.                 v = theEnemies[i].dest.bottom - 2;
  1158.             else
  1159.                 v = (theEnemies[i].dest.top + theEnemies[i].dest.bottom) >> 1;
  1160.             theEnemies[i].dest.left = h - 12;
  1161.             theEnemies[i].dest.right = h + 12;
  1162.             if (theEnemies[i].mode == kSpawning)
  1163.                 theEnemies[i].dest.top = v - 24;
  1164.             else
  1165.                 theEnemies[i].dest.top = v - 12;
  1166.             theEnemies[i].dest.bottom = theEnemies[i].dest.top + 24;
  1167.             theEnemies[i].h = theEnemies[i].dest.left << 4;
  1168.             theEnemies[i].v = theEnemies[i].dest.top << 4;
  1169.             theEnemies[i].mode = kFalling;
  1170.             theEnemies[i].wasDest = theEnemies[i].dest;
  1171.             theEnemies[i].wasH = theEnemies[i].h;
  1172.             theEnemies[i].wasV = theEnemies[i].v;
  1173.             
  1174.             switch (theEnemies[i].kind)
  1175.             {
  1176.                 case kOwl:
  1177.                 theScore += 500L;
  1178.                 break;
  1179.                 
  1180.                 case kWolf:
  1181.                 theScore += 1000L;
  1182.                 break;
  1183.                 
  1184.                 case kJackal:
  1185.                 theScore += 1500L;
  1186.                 break;
  1187.             }
  1188.             UpdateScoreNumbers();
  1189.             PlayExternalSound(kBoom2Sound, kBoom2Priority);
  1190.         }
  1191.         else        // neither player nor enemy killed
  1192.         {
  1193.             if (theEnemies[i].hVel > 0)
  1194.                 theEnemies[i].facingRight = TRUE;
  1195.             else
  1196.                 theEnemies[i].facingRight = FALSE;
  1197.             PlayExternalSound(kScreechSound, kScreechPriority);
  1198.         }
  1199.         
  1200.         wasVel = thePlayer.hVel;
  1201.         thePlayer.hVel = theEnemies[i].hVel;
  1202.         theEnemies[i].hVel = wasVel;
  1203.         wasVel = thePlayer.vVel;
  1204.         thePlayer.vVel = theEnemies[i].vVel;
  1205.         theEnemies[i].vVel = wasVel;
  1206.     }
  1207. }
  1208.  
  1209. //--------------------------------------------------------------  CheckPlayerEnemyCollision
  1210.  
  1211. void CheckPlayerEnemyCollision (void)
  1212. {
  1213.     Rect        whoCares, playTest, wrapTest;
  1214.     short        i;
  1215.     
  1216.     playTest = thePlayer.dest;
  1217.     InsetRect(&playTest, 8, 8);
  1218.     if (thePlayer.wrapping)
  1219.         wrapTest = thePlayer.wrap;
  1220.     InsetRect(&wrapTest, 8, 8);
  1221.     
  1222.     for (i = 0; i < numEnemies; i++)
  1223.     {
  1224.         if ((theEnemies[i].mode != kIdle) && (theEnemies[i].mode != kDeadAndGone))
  1225.         {
  1226.             if (SectRect(&playTest, &theEnemies[i].dest, &whoCares))
  1227.             {
  1228.                 ResolveEnemyPlayerHit(i);
  1229.             }
  1230.             else if (thePlayer.wrapping)
  1231.             {
  1232.                 if (SectRect(&wrapTest, &theEnemies[i].dest, &whoCares))
  1233.                     ResolveEnemyPlayerHit(i);
  1234.             }
  1235.         }
  1236.     }
  1237. }
  1238.  
  1239.